# -*- Mode: Python; tab-width: 4 -*-

# This is the module that implements pymq - The Python based Message Queue
# pymq uses the Medusa HTTP server as it's transport layer
#
# Copyright(C) 2010, Dhruv Matani(dhuvbird@gmail.com)
#
# pymq is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# pymq is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with pymq. If not, see
# <http://www.gnu.org/licenses/>.
#

import os
import socket

import medusa.http_server as http_server
import medusa.monitor as monitor
from request_handler import request_handler
import medusa.status_handler as status_handler
import queue_globals as vars
from medusa import asyncore
from inactive_handler import inactive_handler
from composite_handler import composite_handler
from master_handler import master_handler
from master_notifier import master_notifier
from nop_class import nop_class
from forwarding_proxy import forwarding_proxy
import functools
import config

def onException():
	print "Exception!!"

def run(port, logger, DataStore, inactive, cluster, master,
	    name, connectionString):
	HTTP_PORT		= port
	MONITOR_PORT	= 9999
	HOSTNAME		= config.HOSTNAME
	IP_ADDRESS		= config.LISTEN_IP
	config.PORT     = port

	# ===========================================================================
	# Logging.
	# ===========================================================================

	# There are several types of logging objects. Multiple loggers may be combined,
	# See 'logger.py' for more details.
	lg = logger

	# lg = status_handler.logger_for_status (lg)

	# ===========================================================================
	# Default HTTP handler
	# ===========================================================================

	httpHandler = None
	if master:
		print "Starting pymq master node %s at %s on port %d" % (name, HOSTNAME, port)
		httpHandler = master_handler()
	elif len(cluster) > 0:
		# Start node in clustering mode
		vars.request_handler = request_handler()
		vars.DataStore = DataStore
		masterHost, masterPort = cluster.split(":")
		masterPort = int(masterPort)
		nodeState = "inactive" if inactive else "active"
		print "Starting clustered pymq node %s at %s on port %d in %s mode" % (name, HOSTNAME, port, nodeState)

		if inactive:
			httpHandler = composite_handler()
			iaHandler = inactive_handler(httpHandler, vars.request_handler)
			httpHandler.add_handler(iaHandler)
		else:
			httpHandler = vars.request_handler

		fp = forwarding_proxy(None)
		vars.master_notifier = master_notifier((masterHost, masterPort),
								    		   functools.partial(fp.send_availibility,
													  nodeName=name,
													  nodeHost=socket.gethostbyname(socket.gethostname()),
													  nodePort=port,
													  nodeState=nodeState,
													  connectionString=connectionString),
											   onException=onException)
		fp.set_object(vars.master_notifier)
	else:
		# Start node in stand-alone mode
		print "Starting stand-alone pymq node %s at %s on port %d" % (name, HOSTNAME, port)
		vars.request_handler = request_handler()
		vars.DataStore = DataStore
		httpHandler = vars.request_handler
		vars.master_notifier = nop_class()

	httpHandler.initialize()

	# ===========================================================================
	# HTTP Server
	# ===========================================================================
	hs = http_server.http_server (IP_ADDRESS, HTTP_PORT, logger_object=lg)

	# Here we install the default handler created above.
	hs.install_handler (httpHandler)

	# ===========================================================================
	# Monitor Server:
	# ===========================================================================

	# This creates a secure monitor server, binding to the loopback
	# address on port 9999, with password 'fnord'.  The monitor server
	# can be used to examine and control the server while it is running.
	# If you wish to access the server from another machine, you will
	# need to use '' or some other IP instead of '127.0.0.1'.
	# ms = monitor.secure_monitor_server ('fnord', '127.0.0.1', MONITOR_PORT)

	# ===========================================================================
	# Status Handler
	# ===========================================================================

	# These are objects that can report their status via the HTTP server.
	# You may comment out any of these, or add more of your own.  The only
	# requirement for a 'status-reporting' object is that it have a method
	# 'status' that will return a producer, which will generate an HTML
	# description of the status of the object.

	status_objects = [
		hs,
		# ms,
		# rs,
		lg
		]

	# Create a status handler.  By default it binds to the URI '/status'...
	sh = status_handler.status_extension(status_objects)
	# ... and install it on the web server.
	# hs.install_handler (sh)

	# become 'nobody'
	if os.name == 'posix':
		# import os
		if hasattr (os, 'seteuid'):
			# look in ~medusa/patches for {set,get}euid.
			import pwd
			[uid, gid] = pwd.getpwnam ('nobody')[2:4]
			os.setegid (gid)
			os.seteuid (uid)

	# Finally, start up the server loop!  This loop will not exit until
	# all clients and servers are closed.  You may cleanly shut the system
	# down by sending SIGINT (a.k.a. KeyboardInterrupt).
	asyncore.loop()
